package org.jsola.hr.task;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.jsola.cache.ICache;
import org.jsola.common.BeanKit;
import org.jsola.common.DateKit;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.task.TaskKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IMemoInfoDAO;
import org.jsola.hr.entity.MemoInfoDO;
import org.jsola.hr.entity.TaskDO;
import org.jsola.hr.service.IAttendSysNoticeTaskService;
import org.jsola.hr.service.ICompanySysNoticeTaskService;
import org.jsola.hr.service.IEmpNoticeTaskService;
import org.jsola.hr.service.ITaskService;
import org.jsola.notice.constant.NoticeConstants;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;


/**
 * 启动项目,初始化加载定时任务
 *
 * @author zxy
 */
@Slf4j
@Component
@ConditionalOnProperty(value = "jsola.task.enabled", havingValue = "true")
public class InitializeTask implements CommandLineRunner {

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTask;

    @Autowired
    private ITaskService taskService;

    @Autowired
    private ICache cache;

    @Autowired
    private ICompanySysNoticeTaskService companySysNoticeTaskService;

    @Autowired
    private IEmpNoticeTaskService empNoticeTaskService;

    @Autowired
    private HrSalaryBillTask hrSalaryBillTask;

    @Autowired
    private HrMemoRemindTask hrMemoRemindTask;

    @Autowired
    private IMemoInfoDAO memoInfoDAO;

    @Autowired
    private IAttendSysNoticeTaskService attendSysNoticeTaskService;

    @Override
    public void run(String... args) {
        log.info("启动项目,初始化加载定时任务");
        // 当前时间的下一分钟,对于已过定时,且未执行的,用这个时间执行
        Date nextDate = DateKit.getBeforeMinute(new Date(), 1);
        // 所有待执行的任务
        List<TaskDO> waitTaskList = taskService.listWaitRuning();
        for (TaskDO taskDO : waitTaskList) {
            String subjectType = taskDO.getSubjectType();
            String subjectId = taskDO.getSubjectId();

//            String taskKey = "task:hr:" + subjectType + ":" + subjectId;
            String taskKey = "task:hr:" + taskDO.getId();
            // 看是否已有在执行的
            if (cache != null) {
                if (Objects.nonNull(cache.get(taskKey))) {
                    continue;
                } else {
                    // 放入redis,5分钟
                    cache.set(taskKey, 30 * 1000L, (5 * 60 * 1000));
                }
            }
            Date runDate = taskDO.getRunDate();

            // 对于已过定时,且未执行的,用这个时间执行
            if (runDate.before(new Date())) {
                runDate = nextDate;
            }
            // 根据subjectType获取要执行的定时任务
            Runnable runnable = null;
            //退休和合同续签提醒
            if (NoticeConstants.CONTRACT_EXPIRES.equals(subjectType) || NoticeConstants.RETIRE.equals(subjectType)) {
                runnable = new TaskService(taskDO);
            }
            if (HrConstants.NOTICE_SUBJECT_TYPE_COMPANY.equals(subjectType)) {
                runnable = new companySysNoticeTask(taskDO.getId());
            }
            if (HrConstants.NOTICE_SUBJECT_TYPE_EMP.equals(subjectType)) {
                runnable = new EmpNoticeTask(taskDO.getId());
            }
            if ("salaryBillAutoCheck".equals(subjectType)) {
                runnable = new salaryBillAutoCheckTask(taskDO.getId());
            }
            if (NoticeConstants.MEMO_REMIND.equals(subjectType)) {
                MemoInfoDO memoInfoDO = memoInfoDAO.selectByPrimaryKey(subjectId);
                TokenUser tokenUser = new TokenUser();
                tokenUser.setUserId(memoInfoDO.getCreateUserId());
                tokenUser.setSiteId(memoInfoDO.getSiteId());
                runnable = new MemoRemindSendNoticeTask(taskDO.getId(), tokenUser);
            }
            log.info("执行定时任务,subjectType:{},subjectId:{},runTime:{}", subjectType, subjectId, DateKit.getDateTimeStr(runDate));
            if (runnable != null) {
                threadPoolTask.schedule(runnable, runDate);
            }

            if ("attendNotice".equals(subjectType)) {
                if (taskDO.getRunDate().after(new Date())) {
                    //过期的不要了
                    runnable = new attendPunchRemindTask(taskDO.getId());
                    threadPoolTask.schedule(runnable, taskDO.getRunDate());
                    log.info("项目启动加载考勤打卡通知定时任务：{}", taskDO.getId());
                }
            }
        }
    }

    public class TaskService implements Runnable {

        private final TaskDO task;

        TaskService(TaskDO task) {
            this.task = task;
        }

        @Override
        public void run() {
            if (Objects.nonNull(task)) {
                // 发送通知定时任务
                taskService.runNoticeTask(task.getId());
            }
        }
    }

    public class companySysNoticeTask implements Runnable {
        private final String taskId;

        companySysNoticeTask(String taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            TaskDO task = taskService.selectDOById(taskId, "");
            if (Objects.nonNull(taskId)) {
                log.info("开始执行定时任务{}", task);
                companySysNoticeTaskService.runTask(taskId);
            }
        }
    }

    public class EmpNoticeTask implements Runnable {
        private final String taskId;

        EmpNoticeTask(String taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            TaskDO task = taskService.selectDOById(taskId, "");
            if (Objects.nonNull(taskId)) {
                log.info("开始执行定时任务{}", task);
                empNoticeTaskService.runTask(taskId);
            }
        }
    }

    public class salaryBillAutoCheckTask implements Runnable {
        private final String taskId;

        salaryBillAutoCheckTask(String taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            TaskDO task = taskService.selectDOById(taskId, "");
            if (Objects.nonNull(task)) {
                hrSalaryBillTask.runTask(taskId);
            }
        }
    }

    public class MemoRemindSendNoticeTask implements Runnable {
        private final String taskId;
        private final TokenUser tokenUser;

        MemoRemindSendNoticeTask(String taskId, TokenUser tokenUser) {
            this.taskId = taskId;
            this.tokenUser = tokenUser;
        }

        @Override
        public void run() {
            TaskDO task = taskService.selectDOById(taskId, "");
            if (Objects.nonNull(task)) {
                hrMemoRemindTask.runTask(taskId, tokenUser);
            }
        }
    }


    /**
     * 获取定时任务接口
     *
     * @param runBeanName 接口名称
     * @return 获取定时任务接口
     */
    private Runnable getRunableService(String runBeanName) {
        try {
            return BeanKit.getBean(runBeanName, Runnable.class);
        } catch (Exception e) {
            throw new ParamException("没有实现定时任务接口" + runBeanName);
        }
    }

    public class attendPunchRemindTask implements Runnable {
        private final String taskId;

        attendPunchRemindTask(String taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            TaskDO task = taskService.selectDOById(taskId, "");
            if (Objects.nonNull(task)) {
                attendSysNoticeTaskService.runTask(taskId);
            }
        }
    }
}
